<?php
/**
 * Description: --change here--
 * User: devforma
 * Date: 16/5/26
 * Time: 11:27
 */

class ProcessExerciseBase {

    const SELFTEST_QUESTION_NUM = 10;   //自测题目数量
    
    protected $now;

    protected $userId;                  //用户id
    protected $exerciseId;              //作业id
    protected $exerciseInfo;            //公共作业信息
    protected $extraData;               //非通用数据,各个子类用途不同
    protected $shouldMergeQA = false;   //是否应该进行题目与答案的合并
    protected $selfTestId;


    /**================================
     | 获取作业详情相关属性
     --------------------------------*/
    protected $userExerciseRecord;      //用户-作业记录
    protected $questionIds;             //作业下的题目id
    protected $data = [];                    //返回结果


    /**================================
    | 提交作业相关属性
    --------------------------------*/
    protected $submitArgs;              //提交参数
    protected $submitExerciseRecord;    //待保存或更新的用户-作业记录
    protected $submitResponse;          //响应结果
    
    function __construct() {
        $this->now = date('Y-m-d H:i:s');
    }


    /**
     * 初始化数据
     *
     * @param int $userId 用户id
     * @param object $exercise 作业信息
     * @param object $userExerciseRecord 用户-作业记录
     * @return bool
     */
    private function initData($userId, $exercise, $userExerciseRecord) {
        global $cmsdb;

        $this->userId             = $userId;
        $this->exerciseId         = intval($exercise->id);
        $this->exerciseInfo       = $exercise;
        $this->userExerciseRecord = $userExerciseRecord;
        $this->questionIds        = $cmsdb->getCol('SELECT `question_id` FROM `relation_primary_exercise_question` WHERE `primary_exercise_id`=:eid ORDER BY `id`', [':eid' => $this->exerciseId]);
        if ($this->exerciseInfo->type_id != 31 && empty($this->questionIds)) //非速算作业必须有题目关联
            return false;

        $this->data = array(
            'exercise_id'   => $this->exerciseId,
            'remark'        => array(),
            'exercise_name' => $this->exerciseInfo->name,
            'exercise_type' => isset($this->data['exercise_type']) ? $this->data['exercise_type'] : 0,
            'end_time'      => '',
            'duration'      => (int)$this->exerciseInfo->duration,
            'status'        => 0,
            'status_text'   => '',
            'can_submit'    => true,
            'question'      => null,
            'user_answer'   => null,
            'summary'       => null
        );

        return true;
    }

    /**
     * 设置作业类型,子类需重写
     */
    protected function setExerciseType() {
        $this->data['exercise_type'] = '';
    }

    /**
     * 设置作业题目信息,子类需重写
     */
    protected function setExerciseQuestion() {
        $this->data['question'] = new stdClass();
    }

    /**
     * 设置作业是否有提交权限,子类需重写
     */
    protected function setSubmitPriv() {
        if (in_array($this->data['status'], [0, 4, 6])) //未完成、被驳回、过期
            $this->data['can_submit'] = true;
        else
            $this->data['can_submit'] = false;
    }

    /**
     * 设置作业用户答案,子类需重写
     */
    protected function setUserAnswer() {
        $this->data['user_answer'] = new stdClass();
    }

    /**
     * 设置作业的统计信息
     */
    protected function setSummary() {
        $this->data['summary'] = null;
    }


    /**
     * 获取题目推荐答案
     *
     * @param int $questionId 题目id
     * @param array $recomendRecordIds 推荐记录id数组
     * @return array
     */
    protected function getQuestionRecommendAnswer($questionId, $recomendRecordIds) {
        global $uddb;

        $cacheKey = 'vip:func:getQuestionRecommendAnswer:'.$questionId;
        if (($answers = cacheGet($cacheKey)) == null) {

            //获取被推荐的答题记录
            $recIdStr = implode(',', $recomendRecordIds);
            $sql = "SELECT `user_id`, `user_answer`, `question_id` FROM `history_user_primary_question` WHERE `id` IN ({$recIdStr})";
            $records = (array)$uddb->getResults($sql);

            //获取推荐答案的用户信息
            $userIds = [];
            foreach ($records as $record) {
                $userIds[] = $record->user_id;
            }
            $userIdStr = implode(',', $userIds);
            $usersByUserId = [];
            $users = (array)$uddb->getResults("SELECT `user_id`, `nickname`, `avatar` FROM `user_social_info` WHERE `user_id` IN ($userIdStr)");
            foreach ($users as $u) {
                $usersByUserId[$u->user_id] = [
                    'user_id'  => (int)$u->user_id,
                    'nickname' => $u->nickname,
                    'avatar'   => !empty($u->avatar) && strpos($u->avatar, '://') === false ? 'http://edu.appublisher.com/user-images/avatar/'.$u->avatar : (string)$u->avatar
                ];
            }

            //构建推荐答案结构
            $answers = [];
            foreach ($records as $record) {
                $answers[] = [
                    'user_info' => $usersByUserId[$record->user_id],
                    'user_answer' => html2text($record->user_answer)
                ];
            }

            cacheAdd($cacheKey, $answers, 24*60*60);
        }

        return $answers;
    }

    /**
     * 将用户做题数据合并到题目信息中.
     */
    private function mergeUserAnswer2Question() {
        foreach ($this->data['question'] as &$q) {
            $q['user_answer'] = $this->data['user_answer'][$q['question_id']];
        }
        unset($this->data['user_answer']);
    }

    /**
     * 处理作业
     */
    private function process() {

        //设置作业类型
        $this->setExerciseType();

        //设置作业说明信息
        $this->data['remark'] = $this->getExerciseTypeRemark($this->data['exercise_type']);

        //设置作业题目信息
        $this->setExerciseQuestion();

        if (!empty($this->userExerciseRecord)) { //有用户-作业记录

            //设置作业状态
            $this->data['status'] = (int)$this->userExerciseRecord->status;

            //设置作业结束时间
            $this->data['end_time'] = $this->userExerciseRecord->end_time;

            //设置用户答案字段(需根据用户-作业记录状态来设置)
            $this->setUserAnswer();

            //设置统计信息
            $this->setSummary();

            //多题目则进行答案、题目的合并
            if ($this->shouldMergeQA) {
                $this->mergeUserAnswer2Question();
            }

            //行测智能组卷--为旧数据设置默认答题记录
            if (in_array($this->data['exercise_type'],array(8,21,22,23,24,42))) {
                $this->setDefaultInfoByXingcezhineng();
            }

        } else { //无用户 - 作业记录
            $this->data['status']   = $this->exerciseInfo->end_time > date('Y-m-d H:i:s') ? 0 : 6;
            $this->data['end_time'] = $this->exerciseInfo->end_time;
            //设置统计信息
            $this->setSummary();
        }

        $this->data['status_text'] = VipUtils::getStatusText($this->data['status']);

        //实际用时
        $summary = $this->_getHistoryUserPrimaryExerciseSummary();
        $this->data['cost_time'] = !empty($summary['duration']) ? $summary['duration'] : '';

        //设置提交权限
        $this->setSubmitPriv();
    }

    /**
     * 获取作业详情
     *
     * @param int $userId 用户id
     * @param object $exercise 公共作业信息
     * @param object $userExerciseRecord 用户-作业记录
     * @return array|bool
     */
    public function getExerciseDetail($userId, $exercise, $userExerciseRecord) {
        //数据初始化
        if ($this->initData($userId, $exercise, $userExerciseRecord)) {

            //处理数据主流程
            $this->process();

            return $this->data;
        }

        return false;
    }

    /**
     * 处理数据提交
     *
     * @param int $userId 用户id
     * @param object $exercise 作业信息
     * @return array
     */
    public function submit($userId, $exercise) {
        global $uddb;

        $this->userId       = $userId;
        $this->exerciseId   = intval($exercise->id);
        $this->exerciseInfo = $exercise;

        //查询用户-作业关联
        $this->userExerciseRecord = $uddb->getRow('SELECT * FROM `history_user_primary_exercise` WHERE `user_id`=:uid AND `exercise_id`=:eid',
            array(':uid' => $userId, ':eid' => $this->exerciseId));

        if (!empty($this->userExerciseRecord)) { //已存在用户-作业关联

            //时间更新为
            $this->exerciseInfo->start_time = $this->userExerciseRecord->start_time;
            $this->exerciseInfo->end_time   = $this->userExerciseRecord->end_time;

            //已完成、已提交、过期完成状态,本次提交失效
            if (in_array($this->userExerciseRecord->status, array(1, 3, 5))) {
                return array();
            }

            //作业记录待更新字段
            $this->submitExerciseRecord = array(
                'status' => 0,
//                'summary' => ''
            );

            //更新作业状态
            $this->setSubmitStatus();

            //保存答题记录并更新作业统计
            $this->saveQuestionRecordsAndSetSubmitSummary();

            //更新实际用时
            $this->_setHistoryUserPrimaryExerciseSummary();

            //更新作业记录
            $uddb->update('history_user_primary_exercise', $this->submitExerciseRecord, ['id' => $this->userExerciseRecord->id]);

        } else { //未存在关联
            //作业记录待插入字段
            $this->submitExerciseRecord = [
                'exercise_id' => $this->exerciseId,
                'user_id'     => $userId,
                'start_time'  => $exercise->start_time,
                'end_time'    => $exercise->end_time,
                'status'      => 0,
                'summary'     => ''
            ];

            //更新作业状态
            $this->setSubmitStatus();

            //保存答题记录并更新作业统计
            $this->saveQuestionRecordsAndSetSubmitSummary();

            //更新实际用时
            $this->_setHistoryUserPrimaryExerciseSummary();

            //插入作业记录
            $uddb->insert('history_user_primary_exercise', $this->submitExerciseRecord);
        }

        //附加的动作
        $this->doExtra();

        //设置返回数据
        $this->setSubmitResponseData();

        return $this->submitResponse;
    }

    /**
     * 检测提交作业的参数是否有效
     *
     * @param array $args 参数
     * @return bool
     */
    public function validateArgs($args) {
        $this->submitArgs = $args;
        return true;
    }

    /**
     * 额外的操作,例如提交互评作业时,自动给该用户生成评论其他作业的任务
     */
    protected function doExtra() {}

    /**
     * 设置作业记录的状态
     */
    protected function setSubmitStatus() {
        $this->submitExerciseRecord['status'] = 0;
    }

    /**
     * 保存答题记录并设置作业统计信息
     */
    protected function saveQuestionRecordsAndSetSubmitSummary() {
        $this->submitExerciseRecord['summary'] = '';
    }

    /**
     * 设置提交作业的响应数据
     */
    protected function setSubmitResponseData() {
        $this->submitResponse = array();
    }

    /**
     * 保存答案为空的答题记录
     */
    protected function setDefaultInfoByXingcezhineng() {
        return true;
    }

    /**
     * 获取作业类型说明
     *
     * @param int $typeId 类型id
     * @return array
     */
    private function getExerciseTypeRemark($typeId) {
        global $cmsdb;
        
        $cacheKey = 'vip:func:getExerciseTypeRemark';
        if (($remarks = cacheGet($cacheKey)) == null) {
            $remarks = [];
            $data = $cmsdb->getResults('SELECT * FROM `conf_primary_exercise_type`');
            foreach ($data as $row) {
                $remarks[$row->id] = [
                    'cover_remark'   => $row->content_remark,
                    'content_remark' => $row->content_remark
                ];
            }

            cacheAdd($cacheKey, $remarks, 24*60*60);
        }

        return $remarks[$typeId];
    }

    /**
     * 获取课程名
     *
     * @param int $courseId 课程id
     * @return string
     */
    protected function getCourseName($courseId) {
        global $cmsdb;
        $cacheKey = 'vip:func:getCourseName:'.$courseId;

        if (($courseName = cacheGet($cacheKey)) == null) {
            $courseName = $cmsdb->getVar('SELECT `course_name` FROM `data_live_course` WHERE `id`=:cid', array(':cid' => $courseId));
            cacheAdd($cacheKey, $courseName, 24*60*60);
        }

        return $courseName;
    }

    /**
     * 获取课堂名
     *
     * @param int $classId 课堂id
     * @return string
     */
    protected function getClassName($classId) {
        global $cmsdb;
        $cacheKey = 'vip:func:getClassName:'.$classId;

        if (($className = cacheGet($cacheKey)) == null) {
            $className = $cmsdb->getVar('SELECT `class_name` FROM `data_live_class` WHERE `id`=:cid', [':cid' => $classId]);
            cacheAdd($cacheKey, $className, 24*60*60);
        }

        return $className;
    }

    /**
     * 获取该作业已做人数
     *
     * @return int
     */
    protected function getXingcePersonsNum() {
        global $uddb;

        $cacheKey = 'vip:xingcePersonsNum:'.$this->exerciseId;

        if (($num = cacheGet($cacheKey)) == null) {
            $num = (int)$uddb->getVar('SELECT COUNT(*) FROM `history_user_primary_exercise` WHERE `exercise_id`=:eid', array(':eid' => $this->exerciseId));

            cacheAdd($cacheKey, $num, 24*60*60);
        }

        return $num;
    }

    /**
     * 更新该作业已做人数
     */
    protected function updateXingcePersonsNum() {
        $cacheKey = 'vip:xingcePersonsNum:'.$this->exerciseId;

        $num = $this->getXingcePersonsNum();
        $num++;

        cacheSet($cacheKey, $num, 24*60*60);
    }

    /**
     * 自主答题获取题目信息
     *
     */
    public function getSelfTest($queryArgs) {
        global $uddb;

        //设置题目类型
        $this->setExerciseType();

        $fastestData = $this->getFastestData($queryArgs);

        //答题报告取题
        $questionIds = $answers = [];
        if (!empty($this->selfTestId)) {
            $selfTestRecord = $uddb->getRow('SELECT * FROM `history_user_primary_selftest` WHERE `id`=:id',
                [':id' => $this->selfTestId]);

            $records = $uddb->getResults("SELECT * FROM `history_user_primary_question` WHERE `id` IN ({$selfTestRecord->records}) ORDER BY FIELD(`id`, {$selfTestRecord->records})");


            foreach ($records as $record) {
                $questionIds[] = $record->question_id;

                $answers[$record->question_id] = $record->user_answer;
            }

            $questions = $this->getSelfTestQuestions($questionIds, $answers);

            return [
                'questions' => $questions,
                'summary'   => json_decode($selfTestRecord->summary),
                'level'     => !empty($queryArgs['level']) ? $queryArgs['level']: '',
                'data'      => $fastestData
            ];
        }

        //找数练习抽一道大题(10小题),其他类型抽10道
        $qCount = $this->data['exercise_type'] == 32 ? 1 : self::SELFTEST_QUESTION_NUM;

        return [
            'questions' => $this->getSelfTestQuestions($this->getRandomQuestionIds($qCount), $answers),
            'level'     => !empty($queryArgs['level']) ? $queryArgs['level']: '',
            'data'      => $fastestData
        ];
    }

    /**
     * 自主答题提交数据
     *
     * @param array $args 参数
     * @return null
     */
    protected function submitSelfTest($args) {
        return null;
    }


    /**
     * 随机获取自测题目id
     * @param int $count 抽题数量
     * @return array
     */
    private function getRandomQuestionIds($count) {
        global $cmsdb;

        $allIds = $cmsdb->getCol('SELECT * FROM `original_primary_question` WHERE `exercise_type_id`=:tid', [':tid' => $this->data['exercise_type']]);

        //打乱数组
        shuffle($allIds);

        //取前10个
        return array_slice($allIds, 0, $count);
    }

    /**
     * 获取自测题目
     *
     * @param array $ids 题目id
     * @param array $userAnswers
     * @return null
     */
    protected function getSelfTestQuestions($ids, &$userAnswers) {
        return null;
    }

    /**
     * 设置自测id,用于获取做题报告看错题
     *
     * @param int $selftestId 字测id
     */
    public function setSelfTestId($selftestId) {
        $this->selfTestId = $selftestId;
    }

    /**
     * 通关时间--全站\个人
     *
     * @param $args
     * @return array
     */
    protected function getFastestData($args) {
        return null;
    }

    /**
     * 去除申论题目的题号
     *
     * @param string $text 申论文本
     * @return string
     */
    protected function removeShenlunQNum($text) {
        return str_replace(['第一题、', '第二题、','第三题、','第四题、', '第五题、', '第六题、', '第七题、'], '', $text);
    }

    /**
     * 获取作业实际用时
     *
     * @return int|null|string
     */
    private function _getHistoryUserPrimaryExerciseSummary() {

        $exerciseData = VipUtils::getHistoryUserPrimaryExerciseInfo($this->exerciseId,$this->userId);
        $summary = $exerciseData->summary;

        return  (!empty($summary)) ? json_decode($summary,true) : array() ;
    }

    /**
     * 更新作业实际用时
     *
     */
    private function _setHistoryUserPrimaryExerciseSummary() {

        $summary = json_decode($this->submitExerciseRecord['summary'],true);

        //实际用时--传参是为duration
        if (isset($this->submitArgs['duration']) && !empty($this->submitArgs['duration'])) {
            $summary['duration'] = $this->submitArgs['duration'];
        }
        
        //实际用时--传参是为cost_time
        if (isset($this->submitArgs['cost_time']) && !empty($this->submitArgs['cost_time'])) {

            $summary['duration'] = $this->submitArgs['cost_time'];
        }

        if (!empty($summary))
            $this->submitExerciseRecord['summary'] = json_encode($summary);
        else
            $this->submitExerciseRecord['summary'] = '';
        

    }
}